﻿using ManagementApi.Models;
using ManagementApi.Models.CheckIn;
using ManagementApi.Models.Manage.CheckIn;
using ManagementApi.Models.Manage.ProjectGroup;
using ManagementApi.Models.Manage.ProjectGroupMember;
using ManagementApi.Mvc;
using ManagementApi.Mvc.ApplicationContexts;
using ManagementApi.Services;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using Modules;
using Modules.CheckIn;
using Modules.Project;
using Modules.Reports;
using NPOI.SS.UserModel;
using NPOI.SS.Util;
using NPOI.XSSF.UserModel;
using PmSoft;
using PmSoft.Exceptions;

namespace ManagementApi.Controllers.ManagerPannel
{
    /// <summary>
    /// 项目管理员-考勤相关接口
    /// </summary>
    [Route("/api/v1/manager/checkindetail")]
    [ApiController]
    [Authorize(Roles = "Manager")]
    public class CheckInDetailController : ControllerBase
    {
        private readonly CheckInDetailService checkInDetailService;
        private readonly ProjectManagerApplicationContext applicationContext;
        private readonly PublicCheckinService publicCheckinService;
        private readonly ProjectService projectService;
        private readonly ProjectGroupMemberService projectGroupMemberService;
        private readonly ExportService exportService;
        private readonly ReportProjectGroupDaysService reportProjectGroupDaysService;

        /// <summary>
        /// 构造方法
        /// </summary>
        /// <param name="checkInDetailService"></param>
        /// <param name="applicationContext"></param>
        /// <param name="publicCheckinService"></param>
        /// <param name="projectService"></param>
        /// <param name="exportService"></param>
        /// <param name="projectGroupMemberService"></param>
        /// <param name="reportProjectGroupDaysService"></param>
        public CheckInDetailController(CheckInDetailService checkInDetailService,
            ProjectManagerApplicationContext applicationContext,
           PublicCheckinService publicCheckinService,
           ProjectService projectService,
            ExportService exportService,
            ProjectGroupMemberService projectGroupMemberService,
            ReportProjectGroupDaysService reportProjectGroupDaysService
            )
        {
            this.checkInDetailService = checkInDetailService;
            this.applicationContext = applicationContext;
            this.publicCheckinService = publicCheckinService;
            this.projectService = projectService;
            this.exportService = exportService;
            this.projectGroupMemberService = projectGroupMemberService;
            this.reportProjectGroupDaysService = reportProjectGroupDaysService;
        }

        /// <summary>
        /// 获取考勤记录列表(分页)
        /// </summary>
        /// <param name="query">查询条件</param>
        /// <param name="pageIndex">页码</param>
        /// <param name="pageSize">每页数量</param>
        /// <returns></returns>
        [HttpGet("page")]
        public ApiResult<PageDto<CheckInDetailDto>> GetCheckInDetail([FromQuery] CheckInDetailQuery query, int pageIndex = 1, int pageSize = 20)
        {
            query.ProjectId = applicationContext.CurrentProjectInfo.ProjectId;
            var data = checkInDetailService.GetCheckInDetailMonths(query, pageIndex, pageSize);
            var dtos = data.AsPageDto(source => { return source.AsCheckInDetailDto(applicationContext, applicationContext.CurrentProjectInfo); });
            return ApiResult<PageDto<CheckInDetailDto>>.Success(dtos);
        }

        #region 人员考勤统计

        /// <summary>
        /// 获取按天统计考勤数据
        /// </summary>
        /// <param name="query"></param>
        /// <param name="pageIndex"></param>
        /// <param name="pageSize"></param>
        /// <returns></returns>
        [HttpGet("page_project_day")]
        public ApiResult<PageDto<ReportProjectGroupDays>> GetReportProjectGroupDaysList([FromQuery] ReportProjectGroupDaysQuery query, int pageIndex = 1, int pageSize = 2)
        {
            var data = reportProjectGroupDaysService.GetReportProjectDays(query, pageIndex, pageSize);
            return ApiResult<PageDto<ReportProjectGroupDays>>.Success(data.AsPageDto(source => { return source; }));
        }

        /// <summary>
        /// 人员考勤月统计
        /// </summary>
        /// <param name="query"></param>
        /// <param name="pageNum"></param>
        /// <param name="pageSize"></param>
        /// <returns></returns>
        [HttpGet("page_person_month")]
        public ApiResult<PageDto<CheckInDetailPersonDto>> GetCheckInDetailPerson([FromQuery] CheckInDetailMonthQuery query, int pageNum = 1, int pageSize = 20)
        {
            if (!query.Month.HasValue)
                return ApiResult<PageDto<CheckInDetailPersonDto>>.Failure("请选择一个月份查询");
            if (!query.ProjectId.HasValue) query.ProjectId = applicationContext.CurrentProjectInfo.ProjectId;
            var data = checkInDetailService.GetCheckInDetailsByPersonGroup(query, pageNum, pageSize);
            var dtos = data.AsPageDto(source => { return source.AsDto(applicationContext, applicationContext.CurrentProjectInfo); });
            return ApiResult<PageDto<CheckInDetailPersonDto>>.Success(dtos);
        }

        /// <summary>
        /// 人员考勤月统计
        /// </summary>
        /// <param name="query"></param>
        /// <returns></returns>
        [HttpGet("page_person_month_detail_manager")]
        public ApiResult<IEnumerable<ProjectGroupMemberDto>> GetCheckInDetailPersonsManager([FromQuery] ProjectGroupMemberQuery query, int? month)
        {
            if (!month.HasValue)
                return ApiResult<IEnumerable<ProjectGroupMemberDto>>.Failure("请选择一个月份查询");
            if (!query.ProjectId.HasValue) query.ProjectId = applicationContext.CurrentProjectInfo.ProjectId;
            var data = projectGroupMemberService.GetProjectGroupMembers(query, 1, 9999).Where(i => i.IsManager == true);
            return ApiResult<IEnumerable<ProjectGroupMemberDto>>.Success(data.AsProjectGroupMemberCheckInDtos(month.Value));
        }

        /// <summary>
        /// 人员考勤月统计
        /// </summary>
        /// <param name="query"></param>
        /// <returns></returns>
        [HttpGet("page_person_month_detail_worker")]
        public ApiResult<IEnumerable<ProjectGroupMemberDto>> GetCheckInDetailPersonsWorker([FromQuery] ProjectGroupMemberQuery query, int? month)
        {
            if (!month.HasValue)
                return ApiResult<IEnumerable<ProjectGroupMemberDto>>.Failure("请选择一个月份查询");
            if (!query.ProjectId.HasValue) query.ProjectId = applicationContext.CurrentProjectInfo.ProjectId;

            var data = projectGroupMemberService.GetProjectGroupMembers(query, 1, 9999).OrderByDescending(i => i.IsManager);
            return ApiResult<IEnumerable<ProjectGroupMemberDto>>.Success(data.AsProjectGroupMemberCheckInDtos(month.Value));
        }

        /// <summary>
        /// 查询当前人员信息统计某个月考情详情
        /// </summary>
        /// <param name="memberId"></param>
        /// <param name="month"></param>
        /// <returns></returns>
        [HttpGet("getCheckInDetailPersonForm/{memberId}")]
        public ApiResult<IEnumerable<int>> GetCheckInDetailPersonForm(int memberId, int month)
        {
            var data = checkInDetailService.GetCheckInDetailPersonForm(memberId, month);
            return ApiResult<IEnumerable<int>>.Success(data);
        }

        #endregion 人员考勤统计

        #region 项目考勤统计

        /// <summary>
        /// 项目考勤统计-数量统计
        /// </summary>
        /// <param name="query"></param>
        /// <returns></returns>
        [HttpGet("getProjectCheckinCount")]
        public ApiResult<ProjectCheckinCountDto> GetProjectCheckinCount([FromQuery] ProjectCheckinCountQuery query)
        {
            query.ProjectId = applicationContext.CurrentProjectInfo.ProjectId;
            var dto = publicCheckinService.GetProjectCheckinCount(query);
            return ApiResult<ProjectCheckinCountDto>.Success(dto);
        }

        /// <summary>
        /// 班组考勤分析
        /// </summary>
        /// <param name="query"></param>
        /// <returns></returns>
        [HttpGet("getProjectGroupCheckinAnalysis")]
        public ApiResult<ProjectGroupCheckinAnalysisDto> GetProjectGroupCheckinAnalysis([FromQuery] ProjectCheckinCountQuery query)
        {
            query.ProjectId = applicationContext.CurrentProjectInfo.ProjectId;
            var dto = publicCheckinService.GetProjectGroupCheckinAnalysis(query);
            return ApiResult<ProjectGroupCheckinAnalysisDto>.Success(dto);
        }

        /// <summary>
        /// 导出Excel
        /// </summary>
        /// <returns></returns>
        [HttpGet("export_detail")]
        public IActionResult Export([FromQuery] CheckInDetailQuery query, int pageIndex = 1, int pageSize = 9999)
        {
            query.ProjectId = applicationContext.CurrentProjectInfo.ProjectId;
            var data = checkInDetailService.GetCheckInDetailMonths(query, pageIndex, pageSize);

            List<CheckInDetailExportDto> exportDtos = data.AsExportDtos(applicationContext.CurrentProjectInfo, applicationContext).ToList();
            IWorkbook workbook = ExcelExportHelper.ExportToExcel(exportDtos);

            // 将工作簿保存到内存流中
            using (MemoryStream memoryStream = new())
            {
                workbook.Write(memoryStream);
                // 返回文件内容结果
                return File(memoryStream.ToArray(), "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", $"人员考勤明细_{DateTime.Now.ToString("yyyyMMddHHmmss ")}.xlsx");
            }
        }

        /// <summary>
        /// 导出Excel(人员考勤月统计)
        /// </summary>
        /// <returns></returns>
        [HttpGet("export_month")]
        public IActionResult ExportMonth([FromQuery] CheckInDetailMonthQuery query, int pageIndex = 1, int pageSize = 9999)
        {
            query.ProjectId = applicationContext.CurrentProjectInfo.ProjectId;
            var details = checkInDetailService.GetCheckInDetailsByPersonGroup(query, pageIndex, pageSize);
            IWorkbook workbook = ExcelExportHelper.ExportToExcel(details.AsCheckDetailExportDtos(applicationContext.CurrentProjectInfo,applicationContext).ToList());

            // 将工作簿保存到内存流中
            using (MemoryStream memoryStream = new())
            {
                workbook.Write(memoryStream);
                // 返回文件内容结果
                return File(memoryStream.ToArray(), "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", $"人员考勤明细_{DateTime.Now.ToString("yyyyMMddHHmmss ")}.xlsx");
            }
        }

        /// <summary>
        /// 导出明细
        /// </summary>
        /// <param name="query"></param>
        /// <returns></returns>
        [HttpGet("export")]
        public IActionResult ExportDetail([FromQuery] ProjectCheckinCountQuery query)
        {
            query.ProjectId = applicationContext.CurrentProjectInfo.ProjectId;
            ProjectCheckinCountDto countDto = publicCheckinService.GetProjectCheckinCount(query);
            ProjectGroupCheckinAnalysisDto analysisDto = publicCheckinService.GetProjectGroupCheckinAnalysis(query);

            ProjectInfo? projectInfo = projectService.GetProjectInfo(applicationContext.CurrentProjectInfo.ProjectId) ?? throw new BusinessException($"项目信息不存在");

            #region 生成Excel部分

            // 创建一个新的Excel工作簿
            IWorkbook workbook = new XSSFWorkbook();

            // 创建一个新的工作表
            ISheet sheet = workbook.CreateSheet("Sheet1");
            // 创建列并设置最小宽度
            int columnWidth = 20;
            int columnIndex = 0;
            sheet.SetColumnWidth(columnIndex, columnWidth * 256); // 设定列宽度，参数为1/256个字符宽度

            // 自动调整列宽
            for (int i = 0; i < 8; i++)
            {
                // 自动调整列宽
                //sheet.AutoSizeColumn(i);
                sheet.SetColumnWidth(i, Math.Max(columnWidth * 256, sheet.GetColumnWidth(i)));
            }
            int index = 4;

            #region 表头

            // 合并行和列的方式设置单元格的边界
            CellRangeAddress region = new(0, 1, 0, 7);
            sheet.AddMergedRegion(region);
            // 创建一个新的行
            IRow row = sheet.CreateRow(0);
            ICell cell = row.CreateCell(0);
            // 创建字体对象
            IFont font = workbook.CreateFont();
            font.FontHeightInPoints = 20; // 设置字体大小为 12

            // 设置单元格样式
            ICellStyle cellStyle = workbook.CreateCellStyle();
            cellStyle.Alignment = HorizontalAlignment.Center;//居中
            cellStyle.SetFont(font);
            cell.CellStyle = cellStyle;
            // 设置单元格的值
            cell.SetCellValue($"{projectInfo.Name}{query.Month}考勤统计表");

            #endregion 表头

            #region 中间部分

            exportService.CellRange(sheet, workbook, index, 0, $"项目总人数:{countDto.ProjectPersonCount}", $"出勤总人数:{countDto.CheckinPersonCount}", $"缺勤总人数:{countDto.AbsenceFromDutyPersonCount}");
            index += 2;
            exportService.CellRange(sheet, workbook, index, 0, $"班组数:{countDto.GroupCount}");
            index += 2;
            exportService.CellRange(sheet, workbook, index, 0, $"本月出勤率:{countDto.Attendance}", $"本月缺勤率:{countDto.AbsenceRate}", "");

            index += 2;
            exportService.CellRange(sheet, workbook, index, 0, $"班组考勤分析");
            index++;
            exportService.CellRange(sheet, workbook, index, 0, "序号", "班组名称", "出勤人数", "缺勤人数", "到岗率", "缺勤率");
            index++;

            #region 数据部分

            int rows = 1;
            for (int i = 0; i < analysisDto.GroupNames.Count; i++)
            {
                var groupName = analysisDto.GroupNames[i];
                var checkinPersonCount = analysisDto.CheckinPersonCount[i];
                var absenceFromDutyPersonCount = analysisDto.AbsenceFromDutyPersonCount[i];
                var onDutyRate = analysisDto.OnDutyRate[i];
                var absenceFromDutyRate = analysisDto.AbsenceFromDutyRate[i];
                exportService.CellRange(sheet, workbook, index, 0, rows.ToString(), groupName, checkinPersonCount.ToString(), absenceFromDutyPersonCount.ToString(), onDutyRate.ToString(), absenceFromDutyRate.ToString());
                index++;
                rows++;
            }

            #endregion 数据部分

            #endregion 中间部分

            // 将工作簿保存到内存流中
            using (MemoryStream memoryStream = new())
            {
                workbook.Write(memoryStream);

                // 设置要下载的文件名
                string fileName = $"{projectInfo.Name}{query.Month}考勤统计表.xlsx";

                // 返回文件内容结果
                return File(memoryStream.ToArray(), "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", fileName);
            }

            #endregion 生成Excel部分
        }

        #endregion 项目考勤统计
    }
}